/*
 * Array 求数组的各种集合方法
*/

/**
 * each是一个集合迭代函数，它接受一个函数作为参数和一组可选的参数
 * 这个迭代函数依次将集合的每一个元素和可选参数用函数进行计算，并将计算得的结果集返回
 {%example
 <script>
 var a = [1,2,3,4].each(function(x){return x > 2 ? x : null})
 var b = [1,2,3,4].each(function(x){return x < 0 ? x : null})
 alert(a)
 alert(b)
 </script>
 %}
 * @param {Function} fn 进行迭代判定的函数
 * @param more ... 零个或多个可选的用户自定义参数
 * @returns {Array} 结果集，如果没有结果，返回空集
 */
Array.prototype.each = function (fn) {
  fn = fn || Function.K
  let a = []
  let args = Array.prototype.slice.call(arguments, 1)
  for (let i = 0; i < this.length; i++) {
    let res = fn.apply(this, [this[i], i].concat(args))
    if (res !== null) a.push(res)
  }
  return a
}

/**
 * Array.prototype.[method name] allows you to define/overwrite an objects method
 * needle is the item you are searching for
 * this is a special variable that refers to "this" instance of an Array.
 * returns true if needle is in the array, and false otherwise
 */
Array.prototype.contains = function (needle) {
  let i
  for (i in this) {
    if (this[i] === needle) return true
  }
  return false
}

/**
 * 得到一个数组不重复的元素集合<br/>
 * 唯一化一个数组
 * @returns {Array} 由不重复元素构成的数组
 */

Array.prototype.uniquelize = function () {
  let ra = []
  for (let i = 0; i < this.length; i++) {
    if (!ra.contains(this[i])) {
      ra.push(this[i])
    }
  }
  return ra
}

/**
 * 求两个集合的补集
 {%example
 <script>
 var a = [1,2,3,4]
 var b = [3,4,5,6]
 alert(Array.complement(a,b))
 </script>
 %}
 * @param {Array} a 集合A
 * @param {Array} b 集合B
 * @returns {Array} 两个集合的补集
 */
Array.complement = function (a, b) {
  return Array.minus(Array.union(a, b), Array.intersect(a, b))
}

/**
 * 求两个集合的交集
 {%example
 <script>
 var a = [1,2,3,4]
 var b = [3,4,5,6]
 alert(Array.intersect(a,b))
 </script>
 %}
 * @param {Array} a 集合A
 * @param {Array} b 集合B
 * @returns {Array} 两个集合的交集
 */
Array.intersect = function (a, b) {
  return a.uniquelize().each(function (o) {
    return b.contains(o) ? o : null
  })
}

/**
 * 求两个集合的差集
 {%example
 <script>
 var a = [1,2,3,4]
 var b = [3,4,5,6]
 alert(Array.minus(a,b))
 </script>
 %}
 * @param {Array} a 集合A
 * @param {Array} b 集合B
 * @returns {Array} 两个集合的差集
 */
Array.minus = function (a, b) {
  return a.uniquelize().each(function (o) {
    return b.contains(o) ? null : o
  })
}

/**
 * 求两个集合的并集
 {%example
 <script>
 var a = [1,2,3,4]
 var b = [3,4,5,6]
 alert(Array.union(a,b))
 </script>
 %}
 * @param {Array} a 集合A
 * @param {Array} b 集合B
 * @returns {Array} 两个集合的并集
 */
Array.union = function (a, b) {
  return a.concat(b).uniquelize()
}
